/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.ole.win32.oleclientsite;


private import dwt.dwt;

private import dwt.ole.win32.ole;
private import dwt.ole.win32.oleframe;

private import dwt.internal.win32.os;
private import dwt.internal.compatibility;
private import dwt.internal.ole.win32.com;
private import dwt.internal.ole.win32.OAIDL;
private import dwt.internal.ole.win32.OBJIDL;
private import dwt.internal.ole.win32.OLEIDL;
private import dwt.internal.ole.win32.DOCOBJ;
private import dwt.internal.ole.win32.extras;
private import dwt.internal.ole.win32.ifs;
private import dwt.graphics.point;
private import dwt.graphics.rectangle;
private import dwt.widgets.composite;
private import dwt.widgets.event;
private import dwt.widgets.listener;
private import dwt.widgets.menu;
private import dwt.widgets.shell;
private import dwt.ole.win32.variant;
private import dwt.internal.ole.win32.comtypes;

private import dwt.util.util;




class _IAdviseSinkImpl : IAdviseSink {

	private import std.c.windows.windows;

	OleClientSite	parent;
	this(OleClientSite	p) { parent = p; }
extern (Windows):
	// interface of IUnknown
	HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
	ULONG AddRef()	{ return parent.AddRef(); }
	ULONG Release()	{ return parent.Release(); }

	// interface of IAdviseSink
	void OnDataChange(FORMATETC *pFormatetc,STGMEDIUM *pStgmed) {return ; }
	void OnViewChange(DWORD dwAspect, LONG lindex) {return ; }
	void OnRename(IMoniker pmk) {return ; }
	void OnSave() {return ; }
	void OnClose() {return ; }
}

class _IOleClientSiteImpl : IOleClientSite {

	private import std.c.windows.windows;
	private import std.c.windows.com;

	OleClientSite	parent;
	this(OleClientSite	p) { parent = p; }
extern (Windows):
	// interface of IUnknown
	HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
	ULONG AddRef()	{ return parent.AddRef(); }
	ULONG Release()	{ return parent.Release(); }

	// interface of IOleClientSite
	HRESULT SaveObject() {	if(parent) parent.updateStorage(); return COM.S_OK; }
	HRESULT GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker, IMoniker * ppmk ) {return COM.E_NOTIMPL; }
	HRESULT GetContainer( IOleContainer* ppContainer ) { return parent.GetContainer(ppContainer);}
	HRESULT ShowObject() {
		/* Tells the container to position the object so it is visible to
		 * the user. This method ensures that the container itself is
		 * visible and not minimized.
		 */
		return COM.S_OK;
	}
	HRESULT OnShowWindow(BOOL fShow ) {return COM.S_OK; }
	HRESULT RequestNewObjectLayout() {return COM.E_NOTIMPL; }
}

class  _IOleDocumentSiteImpl : IOleDocumentSite {

	private import std.c.windows.windows;
	private import std.c.windows.com;


	OleClientSite	parent;
	this(OleClientSite	p) { parent = p; }
extern (Windows):
	// interface of IUnknown
	HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
	ULONG AddRef()	{ return parent.AddRef(); }
	ULONG Release()	{ return parent.Release(); }

	// interface of IOleDocumentSite
	HRESULT ActivateMe(IOleDocumentView pViewToActivate) { return parent.ActivateMe(pViewToActivate);}
}

class _IOleInPlaceSiteImpl : IOleInPlaceSite {
	OleClientSite	parent;
	this(OleClientSite	p) { parent = p; }
extern (Windows):
	// interface of IUnknown
	HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
	ULONG AddRef()	{ return parent.AddRef(); }
	ULONG Release()	{ return parent.Release(); }

	// interface of IOleWindow
	HRESULT GetWindow( HWND*  phwnd ) { return parent.GetWindow(phwnd); }
	HRESULT ContextSensitiveHelp( BOOL fEnterMode ) {return COM.S_OK; }

	// interface of IOleInPlaceSite
	HRESULT CanInPlaceActivate() { return parent.CanInPlaceActivate();}
	HRESULT OnInPlaceActivate() { return parent.OnInPlaceActivate(); }
	HRESULT OnUIActivate() { return parent.OnUIActivate(); }
	HRESULT GetWindowContext( IOleInPlaceFrame * ppFrame, IOleInPlaceUIWindow * ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo ) {
		return parent.GetWindowContext(ppFrame, ppDoc, lprcPosRect, lprcClipRect, lpFrameInfo);
	}
	HRESULT Scroll( SIZE scrollExtant ) {return COM.S_OK; }
	HRESULT OnUIDeactivate( BOOL fUndoable ) { return parent.OnUIDeactivate(fUndoable);}
	HRESULT OnInPlaceDeactivate() { return parent.OnInPlaceDeactivate();}
	HRESULT DiscardUndoState() {return COM.E_NOTIMPL; }
	HRESULT DeactivateAndUndo() {return COM.E_NOTIMPL; }
	HRESULT OnPosRectChange( LPCRECT lprcPosRect) { return parent.OnPosRectChange(lprcPosRect);}
}

class _IUnknownImpl : IUnknown
{

	private import std.c.windows.windows;
	private import std.c.windows.com;


	OleClientSite	parent;
	this(OleClientSite	p) { parent = p; }
extern (Windows):
	// interface of IUnknown
	HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
	ULONG AddRef()	{ return parent.AddRef(); }
	ULONG Release()	{ return parent.Release(); }
}

/**
 * OleClientSite provides a site to manage an embedded OLE Document within a container.
 *
 * <p>The OleClientSite provides the following capabilities:
 * <ul>
 *  <li>creates the in-place editor for a blank document or opening an existing OLE Document
 * 	<li>lays the editor out
 *	<li>provides a mechanism for activating and deactivating the Document
 *	<li>provides a mechanism for saving changes made to the document
 * </ul>
 *
 * <p>This object implements the OLE Interfaces IUnknown, IOleClientSite, IAdviseSink,
 * IOleInPlaceSite
 *
 * <p>Note that although this class is a subclass of <code>Composite</code>,
 * it does not make sense to add <code>Control</code> children to it,
 * or set a layout on it.
 * </p><p>
 * <dl>
 *	<dt><b>Styles</b> <dd>BORDER
 *	<dt><b>Events</b> <dd>Dispose, Move, Resize
 * </dl>
 *
 */
public class OleClientSite : Composite {

	private import std.c.windows.windows;
	private import std.c.windows.com;
	private import std.stream;


	// Interfaces for this Ole Client Container
	private _IUnknownImpl	iUnknown;
	private _IOleClientSiteImpl  iOleClientSite;
	private _IAdviseSinkImpl  iAdviseSink;
	private _IOleInPlaceSiteImpl  iOleInPlaceSite;
	private _IOleDocumentSiteImpl  iOleDocumentSite;

	protected GUID* appClsid;
	private GUID* objClsid;

	protected int refCount = 0;

	// References to the associated Frame.
	package OleFrame frame;

	// Access to the embedded/linked Ole Object
	protected IUnknown              objIUnknown;
	protected IOleObject            objIOleObject;
	protected IViewObject2          objIViewObject2;
	protected IOleInPlaceObject     objIOleInPlaceObject;
	protected IOleCommandTarget 	objIOleCommandTarget;
	protected IOleDocumentView    	objDocumentView;

	// Related storage information
	protected IStorage tempStorage;     // _IStorage interface of the receiver

	// Internal state and style information
	private int     aspect;    // the display aspect of the embedded object, e.g., DvaspectContent or DvaspectIcon
	private int     type;      // Indicates the type of client that can be supported inside this container
	private boolean isStatic;  // Indicates item's display is static, i.e., a bitmap, metafile, etc.

	private RECT borderWidths;
	private RECT indent;
	private boolean inUpdate = false;
	private boolean inInit = true;
	private boolean inDispose = false;

//	private static char[] WORDPROGID = "Word.Document"; //$NON-NLS-1$

	private Listener listener;

	enum{
		STATE_NONE = 0,
		STATE_RUNNING = 1,
		STATE_INPLACEACTIVE = 2,
		STATE_UIACTIVE = 3,
		STATE_ACTIVE = 4,
	}
	int state = STATE_NONE;


protected this(Composite parent, int style) {
	/*
	 * NOTE: this constructor should never be used by itself because it does
	 * not create an Ole Object
	 */
	super(parent, style);

	createCOMInterfaces();

	// install the Ole Frame for this Client Site
	while (parent !is null) {
		if (cast(OleFrame)parent){
			frame = cast(OleFrame)parent;
			break;
		}
		parent = parent.getParent();
	}
	if (frame is null) OLE.error (__FILE__, __LINE__, DWT.ERROR_INVALID_ARGUMENT);
	frame.AddRef();

	aspect   = COM.DVASPECT_CONTENT;
	type     = COM.OLEEMBEDDED;
	isStatic = false;

	class LS1 : Listener {
		OleClientSite c;
		public this(OleClientSite o) {c=o;}
		public void handleEvent(Event e) {
			switch (e.type) {
			case DWT.Resize :
			case DWT.Move :    	c.onResize(e); break;
			case DWT.Dispose : 	c.onDispose(e); break;
			case DWT.FocusIn:  	c.onFocusIn(e); break;
			case DWT.FocusOut:  c.onFocusOut(e); break;
			case DWT.Paint:    	c.onPaint(e); break;
			case DWT.Traverse: 	c.onTraverse(e); break;
			case DWT.KeyDown: /* required for traversal */ break;
			default :
				OLE.error (__FILE__, __LINE__, DWT.ERROR_NOT_IMPLEMENTED);
			}
		}
	}
	listener = new LS1(this) ;

	frame.addListener(DWT.Resize, listener);
	frame.addListener(DWT.Move, listener);
	addListener(DWT.Dispose, listener);
	addListener(DWT.FocusIn, listener);
	addListener(DWT.FocusOut, listener);
	addListener(DWT.Paint, listener);
	addListener(DWT.Traverse, listener);
	addListener(DWT.KeyDown, listener);
}
/**
 * Create an OleClientSite child widget using the OLE Document type associated with the
 * specified file.  The OLE Document type is determined either through header information in the file
 * or through a Registry entry for the file extension. Use style bits to select a particular look
 * or set of properties.
 *
 * @param parent a composite widget; must be an OleFrame
 * @param style the bitwise OR'ing of widget styles
 * @param file the file that is to be opened in this OLE Document
 *
 * @exception SWTError
 * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
 *     <li>ERROR_ERROR_NULL_ARGUMENT when the parent is null</ul>
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
 *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
 *     <li>ERROR_CANNOT_OPEN_FILE when failed to open file
 *     <li>ERROR_INTERFACES_NOT_INITIALIZED when unable to create callbacks for OLE Interfaces</ul>
 *
 */

// <Shawn> the argument "fromFile" is not used, only to distinguish from another
// ctor this(Comosite , int, char[] progId)
public this(Composite parent, int style, char[] file, boolean fromFile) {
	this(parent, style);
	try {

		if (file is null || std.file.isdir(file) || !std.file.exists(file))
			OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_ARGUMENT);

		// Is there an associated CLSID?
		appClsid = new GUID();
		wchar* fileName = Converter.StrToWCHARz(file);
		HRESULT result = COM.GetClassFile(fileName, appClsid);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID, result);
		// associated CLSID may not be installed on this machine
		if (getProgramID() is null)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID, result);

		// Open a temporary storage object
		tempStorage = createTempStorage();

		// Create ole object with storage object
		result = COM.OleCreateFromFile(appClsid, fileName, &COM.IIDIUnknown, COM.OLERENDER_DRAW, null, null, tempStorage, cast(void**)&objIUnknown);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);

		// Init sinks
		addObjectReferences();

		if (COM.OleRun(objIUnknown) == OLE.S_OK) state = STATE_RUNNING;
	} catch (Exception e) {
		dispose();
		disposeCOMInterfaces();
		throw e;
	}
}
/**
 * Create an OleClientSite child widget to edit a blank document using the specified OLE Document
 * application.  Use style bits to select a particular look or set of properties.
 *
 * @param parent a composite widget; must be an OleFrame
 * @param style the bitwise OR'ing of widget styles
 * @param progID the unique program identifier of am OLE Document application;
 *               the value of the ProgID key or the value of the VersionIndependentProgID key specified
 *               in the registry for the desired OLE Document (for example, the VersionIndependentProgID
 *               for Word is Word.Document)
 *
 * @exception SWTError
 * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
 *     <li>ERROR_ERROR_NULL_ARGUMENT when the parent is null
 *     <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
 *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
 *     <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
 *     <li>ERROR_INTERFACES_NOT_INITIALIZED when unable to create callbacks for OLE Interfaces</ul>
 *
 */
public this(Composite parent, int style, char[] progId) {
	this(parent, style);
	try {
		appClsid = getClassID(progId);
		if (appClsid is null)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID);

		// Open a temporary storage object
		tempStorage = createTempStorage();

		// Create ole object with storage object
		HRESULT result = COM.OleCreate(appClsid, &COM.IIDIUnknown, COM.OLERENDER_DRAW, null, null, tempStorage, cast(void**)&objIUnknown);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);

		// Init sinks
		addObjectReferences();

		if (COM.OleRun(objIUnknown) == OLE.S_OK)
			state = STATE_RUNNING;

	} catch (Exception e) {
		dispose();
		disposeCOMInterfaces();
		throw e;
	}
}
/**
 * Create an OleClientSite child widget to edit the specified file using the specified OLE Document
 * application.  Use style bits to select a particular look or set of properties.
 * <p>
 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
 * API for <code>OleClientSite</code>. It is marked public only so that it
 * can be shared within the packages provided by DWT. It is not
 * available on all platforms, and should never be called from
 * application code.
 * </p>
 * @param parent a composite widget; must be an OleFrame
 * @param style the bitwise OR'ing of widget styles
 * @param progID the unique program identifier of am OLE Document application;
 *               the value of the ProgID key or the value of the VersionIndependentProgID key specified
 *               in the registry for the desired OLE Document (for example, the VersionIndependentProgID
 *               for Word is Word.Document)
 * @param file the file that is to be opened in this OLE Document
 *
 * @exception SWTError
 * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
 *     <li>ERROR_ERROR_NULL_ARGUMENT when the parent is null
 *     <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
 *     <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
 *     <li>ERROR_CANNOT_OPEN_FILE when failed to open file
 *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
 *     <li>ERROR_INTERFACES_NOT_INITIALIZED when unable to create callbacks for OLE Interfaces</ul>
 *
 */

// TODO: commented all
//public this(Composite parent, int style, String progId, File file) {
//	this(parent, style);
//	try {
//		if (file is null || file.isDirectory() || !file.exists()) OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_ARGUMENT);
//		appClsid = getClassID(progId);
//
//		// Are we opening this file with the preferred OLE object?
//		wchar[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
//		GUID fileClsid = new GUID();
//		COM.GetClassFile(fileName, fileClsid);
//
//		if (COM.IsEqualGUID(appClsid, fileClsid)){
//			// Using the same application that created file, therefore, use default mechanism.
//			tempStorage = createTempStorage();
//			// Create ole object with storage object
//			ComObject address;
//			HRESULT result = COM.OleCreateFromFile(appClsid, fileName, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, 0, tempStorage.getAddress(), address);
//			if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR, result);
//			objIUnknown = new _IUnknown(address[0]);
//		} else {
//			// Not using the same application that created file, therefore, copy from original file to a new storage file
//			_IStorage storage = null;
//			if (COM.StgIsStorageFile(fileName) == COM.S_OK) {
//				ComObject address;
//				int mode = COM.STGM_READ | COM.STGM_TRANSACTED | COM.STGM_SHARE_EXCLUSIVE;
//				HRESULT result = COM.StgOpenStorage(fileName, 0, mode, 0, 0, address); //Does an AddRef if successful
//				if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
//				storage = new _IStorage(address[0]);
//			} else {
//				// Original file is not a Storage file so copy contents to a stream in a new storage file
//				ComObject address;
//				int mode = COM.STGM_READWRITE | COM.STGM_DIRECT | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
//				HRESULT result = COM.StgCreateDocfile(null, mode | COM.STGM_DELETEONRELEASE, 0, address); // Increments ref count if successful
//				if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
//				storage = new _IStorage(address[0]);
//				// Create a stream on the storage object.
//				// Word does not follow the standard and does not use "CONTENTS" as the name of
//				// its primary stream
//				String streamName = "CONTENTS"; //$NON-NLS-1$
//				GUID wordGUID = getClassID(WORDPROGID);
//				if (COM.IsEqualGUID(appClsid, wordGUID)) streamName = "WordDocument"; //$NON-NLS-1$
//				address = new int[1];
//				result = storage.CreateStream(streamName, mode, 0, 0, address); // Increments ref count if successful
//				if (result != COM.S_OK) {
//					storage.Release();
//					OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
//				}
//				IStream stream = new IStream(address[0]);
//				try {
//					// Copy over data in file to named stream
//					FileInputStream fileInput = new FileInputStream(file);
//					int increment = 1024*4;
//					byte[] buffer = new byte[increment];
//					int count = 0;
//					while((count = fileInput.read(buffer)) > 0){
//						int pv = COM.CoTaskMemAlloc(count);
//						OS.MoveMemory(pv, buffer, count);
//						result = stream.Write(pv, count, null) ;
//						COM.CoTaskMemFree(pv);
//						if (result != COM.S_OK) {
//							fileInput.close();
//							stream.Release();
//							storage.Release();
//							OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
//						}
//					}
//					fileInput.close();
//					stream.Commit(COM.STGC_DEFAULT);
//					stream.Release();
//				} catch (StreamException err) {
//					stream.Release();
//					storage.Release();
//					OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE);
//				}
//			}
//
//			// Open a temporary storage object
//			tempStorage = createTempStorage();
//			// Copy over contents of file
//			HRESULT result = storage.CopyTo(0, null, null, tempStorage.getAddress());
//			storage.Release();
//			if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
//
//			// create ole client
//			int[] ppv = new int[1];
//			result = COM.CoCreateInstance(appClsid, 0, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, COM.IIDIUnknown, ppv);
//			if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR, result);
//			objIUnknown = new _IUnknown(ppv[0]);
//			// get the persistant storage of the ole client
//			ppv = new int[1];
//			result = objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv);
//			if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR, result);
//			IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]);
//			// load the contents of the file into the ole client site
//			result = iPersistStorage.Load(tempStorage.getAddress());
//			iPersistStorage.Release();
//			if (result != COM.S_OK)OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
//		}
//
//		// Init sinks
//		addObjectReferences();
//
//		if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
//
//	} catch (SWTException e) {
//		dispose();
//		disposeCOMInterfaces();
//		throw e;
//	}
//}

HRESULT QueryInterface(REFIID riid, void ** ppvObject){
	if (riid is null || ppvObject is null)
		return COM.E_NOINTERFACE;

	if (COM.IsEqualGUID(riid, &COM.IIDIUnknown)) {
		*ppvObject = cast(void*)(cast(IUnknown)iUnknown);
		AddRef();
		return COM.S_OK;
	}
	if (COM.IsEqualGUID(riid, &COM.IIDIAdviseSink)) {
		*ppvObject = cast(void*)(cast(IAdviseSink)iAdviseSink);
		AddRef();
		return COM.S_OK;
	}
	if (COM.IsEqualGUID(riid, &COM.IIDIOleClientSite)) {
		*ppvObject = cast(void*)(cast(IOleClientSite)iOleClientSite);
		AddRef();
		return COM.S_OK;
	}
	if (COM.IsEqualGUID(riid, &COM.IIDIOleInPlaceSite)) {
		*ppvObject = cast(void*)(cast(IOleInPlaceSite)iOleInPlaceSite);
		AddRef();
		return COM.S_OK;
	}
// INTENTIONALLY COMMENTED - see bug 35493
//	if (COM.IsEqualGUID(riid, &COM.IIDIOleDocumentSite )) {
//		String progID = getProgramID();
//		if (!progID.startsWith("PowerPoint")) { //$NON-NLS-1$
//			COM.MoveMemory(ppvObject, new int[] {iOleDocumentSite.getAddress()}, 4);
//			AddRef();
//			return COM.S_OK;
//		}
//	}
	*ppvObject = null;
	return COM.E_NOINTERFACE;
}

ULONG AddRef(){
	return OS.InterlockedIncrement(&refCount);
}

ULONG Release(){
	int ref1 = OS.InterlockedDecrement(&refCount);
	if(ref1 == 0)
		disposeCOMInterfaces();
	return ref1;
}

private HRESULT ActivateMe(IOleDocumentView pViewToActivate) {
	if (pViewToActivate is null) {
		IOleDocument objOleDocument;
		if (objIUnknown.QueryInterface(&COM.IIDIOleDocument, cast(void**)&objOleDocument) != COM.S_OK) return COM.E_FAIL;
		if (objOleDocument.CreateView(iOleInPlaceSite, null, 0, &objDocumentView) != COM.S_OK) return COM.E_FAIL;
		objOleDocument.Release();
	} else {
		objDocumentView = pViewToActivate;
		objDocumentView.AddRef();
		objDocumentView.SetInPlaceSite(iOleInPlaceSite);
	}
	objDocumentView.UIActivate(1);//TRUE
	RECT* rect = getRect();
	objDocumentView.SetRect(rect);
	objDocumentView.Show(1);//TRUE
	return COM.S_OK;
}

protected void addObjectReferences() {
	//
	IPersist objIPersist;

	if (objIUnknown.QueryInterface(&COM.IIDIPersist, cast(void**)&objIPersist) == COM.S_OK) {
		GUID* tempid = new GUID();
		if (objIPersist.GetClassID(tempid) == COM.S_OK)
			objClsid = tempid;
		objIPersist.Release();
	}else{
		Util.trace("QueryInterface(IIDIPersist) failed");
	}

	//
	HRESULT result = objIUnknown.QueryInterface(&COM.IIDIViewObject2, cast(void**)&objIViewObject2);
	if (result != COM.S_OK)
		OLE.error(__FILE__, __LINE__, OLE.ERROR_INTERFACE_NOT_FOUND, result);

	int hr = objIViewObject2.SetAdvise(aspect, 0, iAdviseSink);

	//
	result = objIUnknown.QueryInterface(&COM.IIDIOleObject, cast(void**)&objIOleObject);
	if (result != COM.S_OK)
		OLE.error(__FILE__, __LINE__, OLE.ERROR_INTERFACE_NOT_FOUND, result);
	result = objIOleObject.SetClientSite(iOleClientSite);
	DWORD pdwConnection;
	result = objIOleObject.Advise(iAdviseSink, &pdwConnection);
	result = objIOleObject.SetHostNames("main", "main");  //$NON-NLS-1$ //$NON-NLS-2$

	// Notify the control object that it is embedded in an OLE container
	result = COM.OleSetContainedObject(objIUnknown, true);

	// Is OLE object linked or embedded?
	IOleLink objIOleLink;
	if (objIUnknown.QueryInterface(&COM.IIDIOleLink, cast(void**)&objIOleLink) == COM.S_OK) {
		IMoniker objIMoniker;
		if (objIOleLink.GetSourceMoniker(&objIMoniker) == COM.S_OK) {
			objIMoniker.Release();
			type = COM.OLELINKED;
			objIOleLink.BindIfRunning();
		} else {
			isStatic = true;
		}
		objIOleLink.Release();
	}
}

HRESULT CanInPlaceActivate() {
	if (aspect == COM.DVASPECT_CONTENT && type == COM.OLEEMBEDDED)
		return COM.S_OK;
	return COM.S_FALSE;
}

protected void createCOMInterfaces() {
	iUnknown = new _IUnknownImpl(this);
	iOleClientSite = new _IOleClientSiteImpl(this);
	iAdviseSink = new _IAdviseSinkImpl(this);
	iOleInPlaceSite = new _IOleInPlaceSiteImpl(this);
	iOleDocumentSite = new _IOleDocumentSiteImpl(this);
}

protected IStorage createTempStorage() {
	IStorage tmpStorage;
	int grfMode = COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_DELETEONRELEASE;
	HRESULT result = COM.StgCreateDocfile(null, grfMode, 0, &tmpStorage);
	if (result != COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_FILE, result);
	return (tmpStorage);
}
/**
 * Deactivates an active in-place object and discards the object's undo state.
 */
public void deactivateInPlaceClient() {
	if (objIOleInPlaceObject !is null) {
		objIOleInPlaceObject.InPlaceDeactivate();
	}
}
private void deleteTempStorage() {
	//Destroy this item's contents in the temp root _IStorage.
	if (tempStorage !is null){
		tempStorage.Release();
	}
	tempStorage = null;
}
protected void disposeCOMInterfaces() {
	iUnknown = null;
	iOleClientSite = null;
	iAdviseSink = null;
	iOleInPlaceSite = null;
	iOleDocumentSite = null;
}

/**
 * Requests that the OLE Document or ActiveX Control perform an action; actions are almost always
 * changes to the activation state.
 *
 * @param verb the operation that is requested.  This is one of the OLE.OLEIVERB_ values
 *
 * @return an HRESULT value indicating the success of the operation request; OLE.S_OK indicates
 *         success
 */
public int doVerb(int verb) {
	// Not all OLE clients (for example PowerPoint) can be set into the running state in the constructor.
	// The fix is to ensure that the client is in the running state before invoking any verb on it.

	if (state == STATE_NONE) {
		if (COM.OleRun(objIUnknown) == OLE.S_OK) state = STATE_RUNNING;
	}
	if (state == STATE_NONE || isStatic)
		return COM.E_FAIL;

	// See PR: 1FV9RZW
	HRESULT result = objIOleObject.DoVerb(verb, null, iOleClientSite, 0, handle, null);

	if (state != STATE_RUNNING && inInit) {
		updateStorage();
		inInit = false;
	}
	return result;
}
/**
 * Asks the OLE Document or ActiveX Control to execute a command from a standard
 * list of commands. The OLE Document or ActiveX Control must support the _IOleCommandTarget
 * interface.  The OLE Document or ActiveX Control does not have to support all the commands
 * in the standard list.  To check if a command is supported, you can call queryStatus with
 * the cmdID.
 *
 * @param cmdID the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
 *              commands
 * @param options the optional flags; these are the OLE.OLECMDEXECOPT_ values
 * @param in the argument for the command
 * @param out the return value of the command
 *
 * @return an HRESULT value; OLE.S_OK is returned if successful
 *
 */
public int exec(int cmdID, int options, Variant pvaIn, Variant pvaOut) {

	if (objIOleCommandTarget is null) {
		if (objIUnknown.QueryInterface(&COM.IIDIOleCommandTarget, cast(void**)&objIOleCommandTarget) != COM.S_OK)
			return OLE.ERROR_INTERFACE_NOT_FOUND;
	}

	VARIANT* pIn = null;
	VARIANT* pOut = null;

	if(pvaIn){
		pIn = new VARIANT();
		pvaIn.getData(pIn);
	}
	if(pvaOut){
		pOut = new VARIANT();
		pvaOut.getData(pOut);
	}

	HRESULT result = objIOleCommandTarget.Exec(null, cmdID, options, pIn, pOut);

	if(pIn) {
		COM.VariantClear(pIn);
	}

	if(pOut) {
		pvaOut.setData(pOut);
		COM.VariantClear(pOut);
	}

	return result;
}
HRESULT GetContainer( IOleContainer* ppContainer ) {
	/* Simple containers that do not support links to their embedded
	 * objects probably do not need to implement this method. Instead,
	 * they can return E_NOINTERFACE and set ppContainer to NULL.
	 */
	if (ppContainer !is null) {
		*ppContainer = null;
	}
	return COM.E_NOINTERFACE;
}
HRESULT GetWindow( HWND*  phwnd ) {
	if (phwnd is null)
		return COM.E_INVALIDARG;
	if (frame is null) {
		*phwnd = null;
		return COM.E_NOTIMPL;
	}

	// Copy the Window's handle into the memory passed in
	*phwnd = frame.handle;
	return COM.S_OK;
}
HRESULT GetWindowContext( IOleInPlaceFrame * ppFrame, IOleInPlaceUIWindow * ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo ) {
	if (frame is null || ppFrame is null)
		return COM.E_NOTIMPL;

	// fill in frame handle
	IOleInPlaceFrame iOleInPlaceFrame = frame.getIOleInPlaceFrame();
	*ppFrame = iOleInPlaceFrame;
	frame.AddRef();

	// null out document handle
	if (ppDoc !is null) *ppDoc = null;

	// fill in position and clipping info
	RECT* rect = getRect();
	if (lprcPosRect !is null) *lprcPosRect = *rect;
	if (lprcClipRect !is null) *lprcClipRect = *rect;

	// get frame info
	assert(lpFrameInfo);

	OLEINPLACEFRAMEINFO* frameInfo = lpFrameInfo;
	frameInfo.cb = OLEINPLACEFRAMEINFO.sizeof;
	frameInfo.fMDIApp = 0;
	frameInfo.hwndFrame = frame.handle;
	Shell shell = getShell();
	Menu menubar = shell.getMenuBar();
	if (menubar !is null && !menubar.isDisposed()) {
		HWND hwnd = shell.handle;
		int cAccel = OS.SendMessage(hwnd, OS.WM_APP, 0, 0);
		if (cAccel != 0) {
			HACCEL hAccel = cast(HACCEL)OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
			if (hAccel !is null) {
				frameInfo.cAccelEntries = cAccel;
				frameInfo.haccel = hAccel;
			}
		}
	}

	return COM.S_OK;
}
IDispatch getAutomationObject() {
	IDispatch ppvObject;
	if (objIUnknown.QueryInterface(&COM.IIDIDispatch, cast(void**)&ppvObject) != COM.S_OK)
		return null;
	return ppvObject;
}
protected GUID* getClassID(char[] clientName) {
	// create a GUID struct to hold the result
	GUID* guid = new GUID();

	// create a null terminated array of wchar
	wchar* buffer = null;
	if (clientName !is null) {
		buffer = Converter.StrToWCHARz(clientName);
	}
	if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){
		HRESULT result = COM.CLSIDFromString(buffer, guid);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID, result);
	}
	return guid;
}

private SIZE* getExtent() {
	SIZE* sizel = new SIZE();
	// get the current size of the embedded OLENatives object
	if (objIOleObject !is null) {
		if ( objIViewObject2 !is null && !COM.OleIsRunning(objIOleObject)) {
			objIViewObject2.GetExtent(aspect, -1, null, sizel);
		} else {
			objIOleObject.GetExtent(aspect, sizel);
		}
	}
	return xFormHimetricToPixels(sizel);
}
public Rectangle getIndent() {
	return new Rectangle(indent.left, indent.right, indent.top, indent.bottom);
}
package int getInterface(GUID* iid){
	return 0;
}

/**
 * Returns the program ID of the OLE Document or ActiveX Control.
 *
 * @return the program ID of the OLE Document or ActiveX Control
 */
public char[] getProgramID(){
	if (appClsid !is null){
		BSTR lplpszProgID;
		if (COM.ProgIDFromCLSID(appClsid, &lplpszProgID) == COM.S_OK) {
			// <Shawn Liu> ProgIDFromCLSID(...)
			// lplpszProgID is LPOLESTR type, not BSTR,
			// so don't call StringFromBSTR which calls SysStringByteLen()
			// just pass -1 to determine the null ended to StringFromWCHARz(...)
			char[] s = Converter.WCHARzToStr(lplpszProgID, -1);
			return s;
		}
	}
	return null;
}

RECT* getRect() {
	Point location = this.getLocation();
	Rectangle area = frame.getClientArea();
	RECT* rect = new RECT();
	rect.left   = location.x;
	rect.top    = location.y;
	rect.right  = location.x + area.width - borderWidths.left - borderWidths.right;
	rect.bottom = location.y + area.height - borderWidths.top - borderWidths.bottom;
	return rect;
}

public boolean isDirty() {
	/*
	 *  Note: this method must return true unless it is absolutely clear that the
	 * contents of the Ole Document do not differ from the contents in the file
	 * on the file system.
	 */

	// Get access to the persistant storage mechanism
	IPersistStorage permStorage;
	if (objIOleObject.QueryInterface(&COM.IIDIPersistFile, cast(void**)&permStorage) != COM.S_OK)
		return true;
	// Are the contents of the permanent storage different from the file?
	HRESULT result = permStorage.IsDirty();
	permStorage.Release();
	if (result == COM.S_FALSE) return false;
	return true;
}
public boolean isFocusControl () {
	checkWidget ();
	HWND focusHwnd = OS.GetFocus();
	if (objIOleInPlaceObject is null)
		return (handle is focusHwnd);
	HWND hwnd;
	objIOleInPlaceObject.GetWindow(&hwnd);
	while (focusHwnd !is null) {
		if (hwnd is focusHwnd) return true;
		focusHwnd = OS.GetParent(focusHwnd);
	}
	return false;
}

package void onDispose(Event e) {
	inDispose = true;
	if (state != STATE_NONE)
		doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE);
	deactivateInPlaceClient();
	releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame
	deleteTempStorage();

	// remove listeners
	removeListener(DWT.Dispose, listener);
	removeListener(DWT.FocusIn, listener);
	removeListener(DWT.Paint, listener);
	removeListener(DWT.Traverse, listener);
	removeListener(DWT.KeyDown, listener);
	frame.removeListener(DWT.Resize, listener);
	frame.removeListener(DWT.Move, listener);

	frame.Release();
	frame = null;
}
void onFocusIn(Event e) {
	if (inDispose) return;
	if (state != STATE_UIACTIVE) doVerb(OLE.OLEIVERB_SHOW);
	if (objIOleInPlaceObject is null) return;
	if (isFocusControl()) return;
	HWND hwnd;
	objIOleInPlaceObject.GetWindow(&hwnd);
	if (hwnd is null) return;
	OS.SetFocus(hwnd);
}
void onFocusOut(Event e) {
}

HRESULT OnInPlaceActivate() {
	state = OleClientSite.STATE_INPLACEACTIVE;
	frame.setCurrentDocument(this);
	if (objIOleObject is null)
		return COM.S_OK;

	if (objIOleObject.QueryInterface(&COM.IIDIOleInPlaceObject, cast(void**)&objIOleInPlaceObject) == COM.S_OK) {

	}
	return COM.S_OK;
}
int OnInPlaceDeactivate() {
	if (objIOleInPlaceObject !is null)
		objIOleInPlaceObject.Release();
	objIOleInPlaceObject = null;
	state = OleClientSite.STATE_RUNNING;
	redraw();
	if (getDisplay().getFocusControl() is null) {
		getShell().traverse(DWT.TRAVERSE_TAB_NEXT);
	}
	return COM.S_OK;
}
HRESULT OnPosRectChange( LPCRECT lprcPosRect ) {
	Point size = getSize();
	setExtent(size.x, size.y);
	return COM.S_OK;
}

HRESULT OnUIActivate() {
	if (objIOleInPlaceObject is null) return COM.E_FAIL;
	state = OleClientSite.STATE_UIACTIVE;
	HWND phwnd;
	if (objIOleInPlaceObject.GetWindow(&phwnd) == COM.S_OK) {
		OS.SetWindowPos(phwnd, OS.HWND_TOP, 0, 0, 0, 0, OS.SWP_NOSIZE | OS.SWP_NOMOVE);
	}
	return COM.S_OK;
}

HRESULT OnUIDeactivate( BOOL fUndoable ) {
	// currently, we are ignoring the fUndoable flag
	if (frame is null || frame.isDisposed()) return COM.S_OK;
	state = OleClientSite.STATE_INPLACEACTIVE;
	frame.SetActiveObject(null, null);
	redraw();
	if (getDisplay().getFocusControl() is frame) {
		getShell().traverse(DWT.TRAVERSE_TAB_NEXT);
	}
	Shell shell = getShell();
	Menu menubar = shell.getMenuBar();
	if (menubar is null || menubar.isDisposed())
		return COM.S_OK;

	HWND shellHandle = shell.handle;
	OS.SetMenu(shellHandle, menubar.handle);
	return COM.OleSetMenuDescriptor(null, shellHandle, null, null, null);
}

package void onPaint(Event e) {
	if (state == STATE_RUNNING || state == STATE_INPLACEACTIVE) {
		SIZE* size = getExtent();
		Rectangle area = getClientArea();
		RECT rect;
		if (std.string.find(getProgramID(),"Excel.Sheet") == 0 ) { //$NON-NLS-1$
			rect.left = area.x; rect.right = area.x + (area.height * size.cx / size.cy);
			rect.top = area.y; rect.bottom = area.y + area.height;
		} else {
			rect.left = area.x; rect.right = area.x + size.cx;
			rect.top = area.y; rect.bottom = area.y + size.cy;
		}

		COM.OleDraw(objIUnknown, aspect, e.gc.handle, &rect);
	}
}


package void onResize(Event e) {
	Rectangle area = frame.getClientArea();
	setBounds(borderWidths.left,
		      borderWidths.top,
			  area.width - borderWidths.left - borderWidths.right,
			  area.height - borderWidths.top - borderWidths.bottom);

	setObjectRects();
}




package void onTraverse(Event event) {
	switch (event.detail) {
		case DWT.TRAVERSE_ESCAPE:
		case DWT.TRAVERSE_RETURN:
		case DWT.TRAVERSE_TAB_NEXT:
		case DWT.TRAVERSE_TAB_PREVIOUS:
		case DWT.TRAVERSE_PAGE_NEXT:
		case DWT.TRAVERSE_PAGE_PREVIOUS:
		case DWT.TRAVERSE_MNEMONIC:
			event.doit = true;
			break;
		default : break;
	}
}


/**
 * Returns the status of the specified command.  The status is any bitwise OR'd combination of
 * SWTOLE.OLECMDF_SUPPORTED, SWTOLE.OLECMDF_ENABLED, SWTOLE.OLECMDF_LATCHED, SWTOLE.OLECMDF_NINCHED.
 * You can query the status of a command before invoking it with OleClientSite.exec.  The
 * OLE Document or ActiveX Control must support the _IOleCommandTarget to make use of this method.
 *
 * @param cmd the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
 *            commands
 *
 * @return the status of the specified command or 0 if unable to query the OLE Object; these are the
 *			  OLE.OLECMDF_ values
 */
public int queryStatus(int cmd) {

	if (objIOleCommandTarget is null) {
		if (objIUnknown.QueryInterface(&COM.IIDIOleCommandTarget, cast(void**)&objIOleCommandTarget) != COM.S_OK)
			return 0;
	}

	OLECMD* olecmd = new OLECMD();
	olecmd.cmdID = cmd;

	HRESULT result = objIOleCommandTarget.QueryStatus(null, 1, olecmd, null);

	if (result != COM.S_OK) return 0;

	return olecmd.cmdf;
}

protected void releaseObjectInterfaces() {

	if (objIOleInPlaceObject!is null)
		objIOleInPlaceObject.Release();
	objIOleInPlaceObject = null;

	if (objIOleObject !is null) {
		objIOleObject.Close(COM.OLECLOSE_NOSAVE);
		objIOleObject.Release();
	}
	objIOleObject = null;

	if (objDocumentView !is null){
		objDocumentView.Release();
	}
	objDocumentView = null;

	if (objIViewObject2 !is null) {
		objIViewObject2.SetAdvise(aspect, 0, null);
		objIViewObject2.Release();
	}
	objIViewObject2 = null;

	if (objIOleCommandTarget !is null)
		objIOleCommandTarget.Release();
	objIOleCommandTarget = null;

	if (objIUnknown !is null){
		objIUnknown.Release();
	}
	objIUnknown = null;

	COM.CoFreeUnusedLibraries();
}
public boolean save(File file, boolean includeOleInfo) {
	if (includeOleInfo)
		return saveToStorageFile(file);
	return saveToTraditionalFile(file);
}

// TODO: is the file has opened yet ???
private boolean saveFromContents(IStream address, File file) {

	boolean success = false;

	IStream tempContents = (address);
	tempContents.AddRef();

	try {
//		FileOutputStream writer = new FileOutputStream(file);

		int increment = 1024 * 4;
		LPVOID pv = COM.CoTaskMemAlloc(increment);
		uint cbWritten;
		while (tempContents.Read(pv, increment, &cbWritten) == COM.S_OK && cbWritten > 0) {
			byte[] buffer = new byte[cbWritten];
			OS.MoveMemory(buffer.ptr, pv, cbWritten);
			file.write(cast(ubyte[])buffer); // Note: if file does not exist, this will create the file the
			                      // first time it is called
			success = true;
		}
		COM.CoTaskMemFree(pv);
// TODO: <Shawn> let the caller close the file
//		file.close();

	} catch (Exception err) {
	}

	tempContents.Release();

	return success;
}

// TODO: is the file opened yet ???
private boolean saveFromOle10Native(IStream address, File file) {

	boolean success = false;

	IStream tempContents = (address);
	tempContents.AddRef();

	// The "\1Ole10Native" stream contains a DWORD header whose value is the length
	// of the native data that follows.
	LPVOID pv = COM.CoTaskMemAlloc(4);
	uint size;
	HRESULT rc = tempContents.Read(pv, 4, null);
	OS.MoveMemory(size, pv, 4);
	COM.CoTaskMemFree(pv);
	if (rc == COM.S_OK && size > 0) {

		// Read the data
		byte[] buffer = new byte[size];
		pv = COM.CoTaskMemAlloc(size);
		rc = tempContents.Read(pv, size, null);
		OS.MoveMemory(buffer.ptr, pv, size);
		COM.CoTaskMemFree(pv);

		// open the file and write data into it
		try {
//			FileOutputStream writer = new FileOutputStream(file);
			file.write(cast(ubyte[])buffer); // Note: if file does not exist, this will create the file
//			writer.close();

			success = true;
		} catch (Exception err) {
		}
	}
	tempContents.Release();

	return success;
}

/**
 * Saves the document to the specified file and includes OLE spcific inforrmation.  This method
 * must <b>only</b> be used for files that have an OLE Storage format.  For example, a word file
 * edited with Word.Document should be saved using this method because there is formating information
 * that should be stored in the OLE specific Storage format.
 *
 * @param file the file to which the changes are to be saved
 *
 * @return true if the save was successful
 */

// TODO: how to get filename from a File Object in D???
private boolean saveToStorageFile(File file) {
	Util.trace(__FILE__ , __LINE__ , "not implemented yet");
	return false;

//	// The file will be saved using the formating of the current application - this
//	// may not be the format of the application that was originally used to create the file
//	// e.g. if an Excel file is opened in Word, the Word application will save the file in the
//	// Word format
//	// Note: if the file already exists, some applications will not overwrite the file
//	// In these cases, you should delete the file first (probably save the contents of the file in case the
//	// save fails)
//	if (file is null || file.isDirectory()) return false;
//	if (!updateStorage()) return false;
//
//	// get access to the persistant storage mechanism
//	ComObject address;
//	if (objIOleObject.QueryInterface(COM.IIDIPersistStorage, address) != COM.S_OK) return false;
//	IPersistStorage permStorage = new IPersistStorage(address[0]);
//	try {
//		address = new int[1];
//		wchar[] path = (file.getAbsolutePath()+"\0").toCharArray();
//		int mode = COM.STGM_TRANSACTED | COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
//		HRESULT result = COM.StgCreateDocfile(path, mode, 0, address); //Does an AddRef if successful
//		if (result != COM.S_OK) return false;
//		_IStorage storage =  new _IStorage(address[0]);
//		try {
//			if (COM.OleSave(permStorage.getAddress(), storage.getAddress(), false) == COM.S_OK) {
//				if (storage.Commit(COM.STGC_DEFAULT) == COM.S_OK) {
//					return true;
//				}
//			}
//		} finally {
//			storage.Release();
//		}
//	} finally {
//		permStorage.Release();
//	}
//	return false;
}
/**
 * Saves the document to the specified file.  This method must be used for
 * files that do not have an OLE Storage format.  For example, a bitmap file edited with MSPaint
 * should be saved using this method because bitmap is a standard format that does not include any
 * OLE specific data.
 *
 * @param file the file to which the changes are to be saved
 *
 * @return true if the save was successful
 */
private boolean saveToTraditionalFile(File file) {
	// Note: if the file already exists, some applications will not overwrite the file
	// In these cases, you should delete the file first (probably save the contents of the file in case the
	// save fails)
//	if (file is null || file.isDirectory())
//		return false;
//	if (!updateStorage())
//		return false;
//
//	ComObject address;
//	// Look for a CONTENTS stream
//	if (tempStorage.OpenStream("CONTENTS", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$
//		return saveFromContents(address[0], file);
//
//	// Look for Ole 1.0 object stream
//	if (tempStorage.OpenStream("\1Ole10Native", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$
//		return saveFromOle10Native(address[0], file);

	Util.trace(__FILE__ , ", " , __LINE__ , ", not implemented yet");
	return false;
}

void setBorderSpace(RECT* newBorderwidth) {
	borderWidths = *newBorderwidth;
	// readjust size and location of client site
	Rectangle area = frame.getClientArea();
	setBounds(borderWidths.left, borderWidths.top,
				area.width - borderWidths.left - borderWidths.right,
				area.height - borderWidths.top - borderWidths.bottom);
	setObjectRects();
}
private void setExtent(int width, int height){
	// Resize the width and height of the embedded/linked OLENatives object
	// to the specified values.

	if (objIOleObject is null || isStatic || inUpdate) return;
	SIZE* currentExtent = getExtent();
	if (width == currentExtent.cx && height == currentExtent.cy) return;

	SIZE* newExtent = new SIZE();
	newExtent.cx = width; newExtent.cy = height;
	newExtent = xFormPixelsToHimetric(newExtent);

   // Get the server running first, then do a SetExtent, then show it
	boolean alreadyRunning = COM.OleIsRunning(objIOleObject);
	if (!alreadyRunning)
		COM.OleRun(objIOleObject);

	if (objIOleObject.SetExtent(aspect, newExtent) == COM.S_OK){
		inUpdate = true;
		objIOleObject.Update();
		inUpdate = false;
		if (!alreadyRunning)
			// Close server if it wasn't already running upon entering this method.
			objIOleObject.Close(COM.OLECLOSE_SAVEIFDIRTY);
	}
}
public void setIndent(Rectangle newIndent) {
	indent.left = newIndent.x;
	indent.right = newIndent.width;
	indent.top = newIndent.y;
	indent.bottom = newIndent.height;
}
private void setObjectRects() {
	if (objIOleInPlaceObject is null) return;
	// size the object to fill the available space
	// leave a border
	RECT* rect = getRect();
	objIOleInPlaceObject.SetObjectRects(rect, rect);
}

/**
 * Displays a dialog with the property information for this OLE Object.  The OLE Document or
 * ActiveX Control must support the ISpecifyPropertyPages interface.
 *
 * @param title the name that will appear in the titlebar of the dialog
 */
public void showProperties(char[] title) {

	// Get the Property Page information from the OLE Object
	ISpecifyPropertyPages objISPP;
	if (objIUnknown.QueryInterface(&COM.IIDISpecifyPropertyPages, cast(void**)&objISPP) != COM.S_OK)
		return;
	CAUUID* caGUID = new CAUUID();
	HRESULT result = objISPP.GetPages(caGUID);
	objISPP.Release();
	if (result != COM.S_OK) return;

	// create a frame in which to display the pages
	wchar* chTitle = null;
	if (title !is null) {
		chTitle = Converter.StrToWCHARz(title);
	}
	result = COM.OleCreatePropertyFrame(frame.handle, 10, 10, chTitle, 1, &objIUnknown, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, null);

	// free the property page information
	COM.CoTaskMemFree(caGUID.pElems);
}
private boolean updateStorage() {

	if (tempStorage is null) return false;

	IPersistStorage iPersistStorage;
	if (objIUnknown.QueryInterface(&COM.IIDIPersistStorage, cast(void**)&iPersistStorage) != COM.S_OK)
		return false;

	HRESULT result = COM.OleSave(iPersistStorage, tempStorage, true);

	if (result != COM.S_OK){
		// OleSave will fail for static objects, so do what OleSave does.
		COM.WriteClassStg(tempStorage, objClsid);
		result = iPersistStorage.Save(tempStorage, true);
	}

	tempStorage.Commit(COM.STGC_DEFAULT);
	result = iPersistStorage.SaveCompleted(null);
	iPersistStorage.Release();

	return true;
}
private SIZE* xFormHimetricToPixels(SIZE* aSize) {
	// Return a new Size which is the pixel transformation of a
	// size in HIMETRIC units.

	HDC hDC = OS.GetDC (null);
	int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
	int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
	OS.ReleaseDC (null, hDC);
	int cx = Compatibility.round(aSize.cx * xppi, 2540); // 2540 HIMETRIC units per inch
	int cy = Compatibility.round(aSize.cy * yppi, 2540);
	SIZE* size = new SIZE();
	size.cx = cx;
	size.cy = cy;
	return size;
}
private SIZE* xFormPixelsToHimetric(SIZE* aSize) {
	// Return a new size which is the HIMETRIC transformation of a
	// size in pixel units.

	HDC hDC = OS.GetDC (null);
	int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
	int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
	OS.ReleaseDC (null, hDC);
	int cx = Compatibility.round(aSize.cx * 2540, xppi); // 2540 HIMETRIC units per inch
	int cy = Compatibility.round(aSize.cy * 2540, yppi);
	SIZE* size = new SIZE();
	size.cx = cx;
	size.cy = cy;
	return size;
}
}
